﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

namespace Transfer.CrossDocument
{
	public class AutoCopyEntitiesManager
	{
		public AutoCopyEntitiesManager(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
		}

		public void Copy(Autodesk.Revit.DB.Document sourceDoc, Transform transform, List<List<ElementId>> generalElements, bool copyWindows, bool copyDoors, bool copyOpenings)
		{
			Document document = this.m_Revit.Application.ActiveUIDocument.Document;
			foreach (List<ElementId> list in generalElements)
			{
				if (list.Count != 0)
				{
					List<ElementId> newElementIds = new List<ElementId>();
					this.CopyElementsCrossDocument(sourceDoc, list, document, transform, ref newElementIds);
					this.DeleteBaseWallElements(newElementIds, copyWindows, copyDoors, copyOpenings);
				}
			}
		}

		private bool CopyElementsCrossDocument(Autodesk.Revit.DB.Document fromDocument, List<ElementId> elementIds, Autodesk.Revit.DB.Document toDocument, Transform tran, ref List<ElementId> newElementIds)
		{
			using (Transaction transaction = new Transaction(toDocument, "copy elements"))
			{
				transaction.Start();
				try
				{
					ICollection<ElementId> collection = RevitVersionFuncs.CopyElements(fromDocument, elementIds, toDocument, tran);
					newElementIds.AddRange(collection);
				}
				catch (Exception ex)
				{
					ex.ToString();
					transaction.RollBack();
					return false;
				}
				FailureHandlingOptions failureHandlingOptions = transaction.GetFailureHandlingOptions();
				failureHandlingOptions.SetFailuresPreprocessor(new HidePasteDuplicateTypesPreprocessor());
				transaction.Commit(failureHandlingOptions);
			}
			return true;
		}

		private void DeleteBaseWallElements(List<ElementId> newElementIds, bool copyWindows, bool copyDoors, bool copyOpenings)
		{
			if (newElementIds.Count == 0)
			{
				return;
			}
			Document document = this.m_Revit.Application.ActiveUIDocument.Document;
			if (document.GetElement(newElementIds[0]).GetType() != typeof(Wall))
			{
				return;
			}
			List<ElementId> list = new List<ElementId>();
			foreach (ElementId elementId in newElementIds)
			{
				Wall wall = document.GetElement(elementId) as Wall;
				if (!copyWindows)
				{
					list.AddRange(this.GetBaseWallElements(document, wall, typeof(FamilyInstance), BuiltInCategory.OST_Windows));
				}
				if (!copyDoors)
				{
					list.AddRange(this.GetBaseWallElements(document, wall, typeof(FamilyInstance), BuiltInCategory.OST_Doors));
				}
				if (!copyOpenings)
				{
					list.AddRange(this.GetBaseWallElements(document, wall, typeof(Opening), BuiltInCategory.OST_SWallRectOpening));
					list.AddRange(this.GetBaseWallElements(document, wall, typeof(Opening), BuiltInCategory.OST_ArcWallRectOpening));
				}
			}
			this.DeleteElements(document, list);
		}

		private void DeleteElements(Autodesk.Revit.DB.Document doc, List<ElementId> elements)
		{
			if (elements.Count == 0)
			{
				return;
			}
			using (Transaction transaction = new Transaction(doc, "delete elements"))
			{
				transaction.Start();
				foreach (ElementId elementId in elements)
				{
					try
					{
						doc.Delete(elementId);
					}
					catch (Exception)
					{
					}
				}
				transaction.Commit();
			}
		}

		private List<ElementId> GetBaseWallElements(Autodesk.Revit.DB.Document doc, Wall wall, Type type, BuiltInCategory category)
		{
			List<ElementId> list = new List<ElementId>();
			ElementCategoryFilter elementCategoryFilter = new ElementCategoryFilter(category);
			IEnumerable<Element> enumerable = new FilteredElementCollector(doc).OfClass(type).WherePasses(elementCategoryFilter).ToElements();
			ElementId elementId = wall.get_Parameter(BuiltInParameter.ID_PARAM).AsElementId();
			foreach (Element element in enumerable)
			{
				ElementId obj;
				if (element.GetType() == typeof(FamilyInstance))
				{
					obj = (element as FamilyInstance).Host.get_Parameter(BuiltInParameter.ID_PARAM).AsElementId();
				}
				else
				{
					if (!(element.GetType() == typeof(Opening)))
					{
						continue;
					}
					obj = (element as Opening).Host.Id;
				}
				if (elementId.Equals(obj))
				{
					list.Add(element.Id);
				}
			}
			return list;
		}

		private ExternalCommandData m_Revit;
	}
}
